package edu.bbu.cshu.wmpc.checking;

import java.util.ArrayList;
import edu.bbu.cshu.wmpc.core.FileTypes;
import edu.bbu.cshu.wmpc.core.LevelTypes;
import edu.bbu.cshu.wmpc.core.SourceCodeWmpc;
import edu.bbu.cshu.wmpc.core.TestTypes;
import edu.bbu.cshu.wmpc.formalization.Context;
import edu.bbu.cshu.wmpc.formalization.CCppSource.ConcrateCcppFormalization;
import edu.bbu.cshu.wmpc.formalization.JavaSource.ConcrateJavaFormalization;
import edu.bbu.cshu.wmpc.formalization.PascalSource.ConcratePascalFormalization;

/**
 * <ul>
 * <li><b><i>PerformAllTests</i></b></li>
 * <li style="list-style: none;"></li>
 * <li style="list-style: none;">
 * Enumeration used to execute a group of tests between two given source code {@code Objects}, taking into account the roughness specified by the given {@code level}.
 * 
 * @author WMPC team
 * </li>
 * </ul>
 */ 
public enum PerformAllTests {
	/**
	 * <ul>
	 * <li><b><i>INSTANCE</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * Ensures that only a single instance of the enumeration exists.
	 * 
	 * </li>
	 * </ul>
	 */
	INSTANCE;
	/**
	 * <ul>
	 * <li><b><i>testsToDo</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * {@code {@link ArrayList}<{@link TestTypes}> containing tests to be performed.
	 * 
	 * </li>
	 * </ul>
	 */
	private ArrayList<TestTypes> testsToDo = new ArrayList<TestTypes>();
	/**
	 * <ul style="margin-top: 24px;">
	 * <li><b><i>setTestsToDo</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * <p style="margin-left: 7px;">{@code public void setTestsToDo(}{@link ArrayList}<{@link TestTypes}> {@code tests)}</p>
	 * <br>	
	 * Sets the tests to be performed.  
	 * 
	 * @param tests - a list of tests that are to be performed
	 * </li>
	 * </ul>
	 */
	public void setTestsToDo(ArrayList<TestTypes> tests) {
		testsToDo = tests;
	}	
	/**
	 * <ul style="margin-top: 24px;">
	 * <li><b><i>performTests</i></b></li>
	 * <li style="list-style: none;"></li>
	 * <li style="list-style: none;">
	 * <p style="margin-left: 7px;">{@code public} {@link ArrayList}<{@link Object}> {@code performTests(}{@link LevelTypes} {@code level,} {@link SourceCodeWmpc} {@code sc1,} {@link SourceCodeWmpc} {@code sc2)}</p>
	 * <br>	
	 * Executes all tests predefined in {@code testsToDo} between {@code sc1} and {@code sc2}, taking into account the roughness specified by the {@code level}. 
	 * 
	 * @param level - specifies the level of the tests to be performed
	 * @param sc1   - first source code {@code Object}
	 * @param sc2   - second source code {@code Object}
	 * @return      an {@code ArrayList<Object>} containing all the test results
	 * </li>
	 * </ul>
	 */
	public ArrayList<Object> performTests(LevelTypes level, SourceCodeWmpc sc1, SourceCodeWmpc sc2) {
		ArrayList<Object> results = new ArrayList<Object>();
		FileTypes type = sc1.getType();
		
		switch (type) {
			case CPP:
				Context.INSTANCE.setStrategy(new ConcrateCcppFormalization(sc1));
				sc1 = Context.INSTANCE.executeFormalization(level);
				Context.INSTANCE.setStrategy(new ConcrateCcppFormalization(sc2));
				sc2 = Context.INSTANCE.executeFormalization(level);
				break;
			case JAVA:
				Context.INSTANCE.setStrategy(new ConcrateJavaFormalization(sc1));
				sc1 = Context.INSTANCE.executeFormalization(level);
				Context.INSTANCE.setStrategy(new ConcrateJavaFormalization(sc2));
				sc2 = Context.INSTANCE.executeFormalization(level);
				break;
			case PASCAL:
				Context.INSTANCE.setStrategy(new ConcratePascalFormalization(sc1));
				sc1 = Context.INSTANCE.executeFormalization(level);
				Context.INSTANCE.setStrategy(new ConcratePascalFormalization(sc2));
				sc2 = Context.INSTANCE.executeFormalization(level);
				break;
		}
		
		for (int k = 0; k < testsToDo.size(); k++) {
			TestFactory.INSTANCE.setTestType(testsToDo.get(k));
			results.addAll(TestFactory.INSTANCE.getTester().executeTest(level,sc1, sc2));
		}
		
		return results;
	}
}
